package com.example.service;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.common.PageResult;
import com.example.common.enums.ErrorCodeEnum;
import com.example.common.enums.OrdersStatusEnum;
import com.example.common.enums.RoleEnum;
import com.example.exception.CustomException;
import com.example.mapper.GoodsOrdersMapper;
import com.example.pojo.dto.GoodsOrdersAddDto;
import com.example.pojo.dto.GoodsOrdersQueryDto;
import com.example.pojo.entity.*;
import com.example.pojo.vo.GoodsOrdersQueryVo;
import com.example.utils.AccountUtils;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 宠物用品订单 service 层实现类
 */
@Service
public class GoodsOrdersServiceImpl extends ServiceImpl<GoodsOrdersMapper, GoodsOrders> implements GoodsOrdersService {

    @Resource
    private UserService userService;

    @Resource
    private PetShopService petShopService;

    @Resource
    private GoodsService goodsService;

    @Resource
    private AddressService addressService;

    @Resource
    private CartService cartService;

    /**
     * 创建宠物用品订单
     *
     * @param dtoList 宠物用品订单
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void add(List<GoodsOrdersAddDto> dtoList) {
        // 1.校验参数
        if (CollectionUtil.isEmpty(dtoList)) {
            throw new CustomException(ErrorCodeEnum.PARAM_LOST_ERROR);
        }
        // 2.获取当前用户且校验是否是普通用户
        User dbUser = this.getUserAndCheck();

        // 3.对于每个宠物用品创建一个订单
        for (GoodsOrdersAddDto dto : dtoList) {
            this.createOrders(dbUser, dto);
        }

        // 4.将订单的宠物用品移出购物车
        List<Integer> cartIdList = dtoList.stream()
                .map(GoodsOrdersAddDto::getCartId)
                .collect(Collectors.toList());
        this.cartService.lambdaUpdate()
                .in(Cart::getId, cartIdList)
                .remove();
    }

    /**
     * 对于每个宠物用品创建一个订单
     *
     * @param dbUser 普通用户
     * @param dto 参数
     */
    @Transactional(rollbackFor = Exception.class)
    public void createOrders(User dbUser, GoodsOrdersAddDto dto) {
        // 获取订单的宠物用品
        Goods dbGoods = this.goodsService.lambdaQuery()
                .eq(Goods::getId, dto.getGoodsId())
                .one();
        // 获取收货地址
        Address dbAddress = this.addressService.lambdaQuery()
                .eq(Address::getId, dto.getAddressId())
                .one();
        // 2.生成宠物订单 - 前端只传宠物用品id、宠物店id、收货地址id、宠物用品数量
        GoodsOrders goodsOrders = new GoodsOrders();
        // 2.1 订单号：yyyyMMdd+时问戳
        String ordersNo = DateUtil.format(new Date(), "yyyyMMdd") + System.currentTimeMillis();
        goodsOrders.setOrderNo(ordersNo);
        // 2.2 普通用户id
        goodsOrders.setUserId(dbUser.getId());
        // 2.3 宠物店id、宠物用品id由前端传来
        goodsOrders.setGoodsId(dto.getGoodsId());
        goodsOrders.setShopId(dto.getShopId());
        // 2.4 宠物用品名称、宠物用品图片、宠物用品价格由宠物用品id查出
        goodsOrders.setGoodsName(dbGoods.getName());
        goodsOrders.setGoodsImage(dbGoods.getImage());
        goodsOrders.setPrice(dbGoods.getPrice());
        // 2.5 宠物用品数量
        goodsOrders.setGoodsNumber(dto.getGoodsNumber());
        // 2.6 收货地址id由前端传来，收货人姓名、收货人地址、收货人电话号由收货地址id查出
        goodsOrders.setPickupAddress(dbAddress.getAddress());
        goodsOrders.setPickupName(dbAddress.getName());
        goodsOrders.setPickupPhone(dbAddress.getPhone());
        // 2.7 刚创建订单时订单状态为待支付
        goodsOrders.setStatus(OrdersStatusEnum.CREATED.getName());
        // 2.8 创建时间
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        String formatTime = LocalDateTime.now().format(dateTimeFormatter);
        goodsOrders.setCreateTime(formatTime);

        // 3.将宠物订单存入数据库
        this.save(goodsOrders);
    }

    /**
     * 分页查询宠物用品订单
     *
     * @param pageNum  页码
     * @param pageSize 页大小
     * @param dto      条件
     * @return 分页结果
     */
    @Override
    public PageResult<GoodsOrdersQueryVo> pageQuery(Integer pageNum, Integer pageSize, GoodsOrdersQueryDto dto) {
        // 1.校验参数
        if (pageNum == null || pageNum < 1) {
            throw new CustomException(ErrorCodeEnum.PAGE_QUERY_NUM);
        }
        if (pageSize == null || pageSize < 1 || pageSize > 100) {
            throw new CustomException(ErrorCodeEnum.PAGE_QUERY_SIZE);
        }

        // 2.创建 MybatisPlus 分页对象
        IPage<GoodsOrdersQueryVo> pageObject = new Page<>(pageNum, pageSize);

        // 3.获取当前登录的用户
        Account currentLoginAccount = AccountUtils.getCurrentLoginAccount();
        if (currentLoginAccount == null || StrUtil.isBlank(currentLoginAccount.getRole())) {
            throw new CustomException(ErrorCodeEnum.GET_CUR_USER_ERROR);
        }
        String role = currentLoginAccount.getRole();
        String username = currentLoginAccount.getUsername();

        if (RoleEnum.USER.name().equals(role)) {
            // 4.1 当前登录的用户是普通用户，只查询自己的宠物用品订单
            Integer userId = this.userService.lambdaQuery()
                    .eq(User::getUsername, username)
                    .one()
                    .getId();
            dto.setUserId(userId);
        } else if (RoleEnum.PETSHOP.name().equals(role)) {
            // 4.2 当前登录的用户是宠物店，只查询自己的宠物用品订单
            Integer shopId = this.petShopService.lambdaQuery()
                    .eq(PetShop::getUsername, username)
                    .one()
                    .getId();
            dto.setShopId(shopId);
        }
        // 4.3 当前登录的用户是管理员，按条件查询全部的宠物用品订单

        // 5.分页查询宠物订单
        pageObject = this.getBaseMapper().pageQuery(pageObject, dto);

        // 6.构建分页结果并返回
        return new PageResult<>(
                pageObject.getTotal(),
                pageObject.getRecords()
        );
    }

    /**
     * 普通用户取消订单
     *
     * @param id 订单id
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void cancel(Integer id) {
        // 1.校验订单id
        if (id == null) {
            throw new CustomException(ErrorCodeEnum.PARAM_LOST_ERROR);
        }

        // 2.当前用户只能是普通用户才可以取消订单
        this.getUserAndCheck();

        // 3.获取订单
        GoodsOrders dbGoodsOrders = this.lambdaQuery()
                .eq(GoodsOrders::getId, id)
                .one();

        // 4.订单状态只有待支付才可以取消订单
        if (!OrdersStatusEnum.CREATED.getName().equals(dbGoodsOrders.getStatus())) {
            throw new CustomException(ErrorCodeEnum.CANCEL_ONLY_PAY_BEFORE_ERROR);
        }

        // 5.修改订单状态为"已取消"
        this.lambdaUpdate()
                .eq(GoodsOrders::getId, id)
                .set(GoodsOrders::getStatus, OrdersStatusEnum.CANCEL.getName())
                .update();
    }

    /**
     * 普通用户支付订单
     *
     * @param id 订单id
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void pay(Integer id) {
        // 1.校验订单id
        if (id == null) {
            throw new CustomException(ErrorCodeEnum.PARAM_LOST_ERROR);
        }

        // 2.当前用户只能是普通用户才可以支付订单
        User dbUser = this.getUserAndCheck();

        // 3.获取数据
        // 获取订单
        GoodsOrders dbGoodsOrders = this.lambdaQuery().eq(GoodsOrders::getId, id).one();
        // 获取宠物用品
        Goods dbGoods = this.goodsService.lambdaQuery().eq(Goods::getId, dbGoodsOrders.getGoodsId()).one();


        // 普通用户支付订单，订单状态变为"待发货"，宠物用品库存 - 订单的宠物用品数量, 宠物用品销量 + 订单的宠物用品数量, 普通用户余额 - (宠物用品价格 * 订单的宠物用品数量)
        // 4.修改宠物订单状态
        this.lambdaUpdate()
                .eq(GoodsOrders::getId, id)
                .set(GoodsOrders::getStatus, OrdersStatusEnum.PAYED.getName())
                .update();

        // 5.修改宠物用品库存
        // 5.1 校验宠物用品是否还有库存
        if (dbGoods.getStore() < dbGoodsOrders.getGoodsNumber()) {
            throw new CustomException(ErrorCodeEnum.GOODS_STORE_IS_NULL_ERROR);
        }
        // 5.2 宠物用品库存 - 订单的宠物用品数量
        this.goodsService.lambdaUpdate()
                .eq(Goods::getId, dbGoods.getId())
                .set(Goods::getStore, dbGoods.getStore() - dbGoodsOrders.getGoodsNumber())
                .update();

        // 6.修改宠物用品销量
        // 宠物用品销量 + 订单的宠物用品数量
        this.goodsService.lambdaUpdate()
                .eq(Goods::getId, dbGoods.getId())
                .set(Goods::getSale, dbGoods.getSale() + dbGoodsOrders.getGoodsNumber())
                .update();

        // 7.修改普通用户余额
        // 7.1 算出总价格
        BigDecimal totalPrice = dbGoods.getPrice().multiply(BigDecimal.valueOf(dbGoodsOrders.getGoodsNumber()));
        // 7.2 校验普通用户是否还有足够余额
        if (dbUser.getAccount().compareTo(totalPrice) < 0) {
            throw new CustomException(ErrorCodeEnum.USER_AMOUNT_NOT_ENOUGH_ERROR);
        }
        // 7.3 普通用户余额 - (宠物用品价格 * 订单的宠物用品数量)
        this.userService.lambdaUpdate()
                .eq(User::getId, dbUser.getId())
                .set(User::getAccount, dbUser.getAccount().subtract(totalPrice))
                .update();
    }

    /**
     * 宠物店发货
     *
     * @param id 订单id
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void send(Integer id) {
        // 1.校验订单id
        if (id == null) {
            throw new CustomException(ErrorCodeEnum.PARAM_LOST_ERROR);
        }

        // 2.当前用户只有是宠物店才可以发货
        Account currentLoginAccount = AccountUtils.getCurrentLoginAccount();
        if (currentLoginAccount == null) {
            throw new CustomException(ErrorCodeEnum.GET_CUR_USER_ERROR);
        }
        String role = currentLoginAccount.getRole();
        if (!RoleEnum.PETSHOP.name().equals(role)) {
            throw new CustomException(ErrorCodeEnum.ONLY_SHOP_SEND);
        }

        // 3.宠物店发货，订单变为"待签收"状态
        this.lambdaUpdate()
                .eq(GoodsOrders::getId, id)
                .set(GoodsOrders::getStatus, OrdersStatusEnum.SEND.getName())
                .update();
    }

    /**
     * 普通用户签收
     *
     * @param id 订单id
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void sign(Integer id) {
        // 1.校验订单id
        if (id == null) {
            throw new CustomException(ErrorCodeEnum.PARAM_LOST_ERROR);
        }

        // 2.当前用户只有是普通用户才可以签收
        this.getUserAndCheck();

        // 3.普通用户签收，订单变为"已完成"状态
        this.lambdaUpdate()
                .eq(GoodsOrders::getId, id)
                .set(GoodsOrders::getStatus, OrdersStatusEnum.SIGN.getName())
                .update();
    }

    /**
     * 统计宠物用品销售额
     *
     * @param shopId 宠物店id
     * @param start 开始时间
     * @param end 结束时间
     * @return 宠物用品销售额
     */
    @Override
    public BigDecimal countSale(Integer shopId, String start, String end) {
        return this.getBaseMapper().countSale(shopId, start, end);
    }

    /**
     * 获取当前用户且校验是否是普通用户
     *
     * @return 普通用户
     */
    private User getUserAndCheck() {
        // 1.获取当前登录的账户
        Account currentLoginAccount = AccountUtils.getCurrentLoginAccount();
        if (currentLoginAccount == null) {
            throw new CustomException(ErrorCodeEnum.GET_CUR_USER_ERROR);
        }
        // 2.判断当前当前登录的是否是普通用户
        if (!RoleEnum.USER.name().equals(currentLoginAccount.getRole())) {
            throw new CustomException(ErrorCodeEnum.ONLY_USER_CREATE_ORDER);
        }
        // 3.查询普通用户
        User dbUser = this.userService.lambdaQuery()
                .eq(User::getUsername, currentLoginAccount.getUsername())
                .one();
        if (dbUser == null) {
            throw new CustomException(ErrorCodeEnum.GET_CUR_USER_ERROR);
        }
        // 4.返回当前登录的普通用户
        return dbUser;
    }
}
